package com.bf.electroplating.util.idempotent;

import com.bf.electroplating.config.exception.IdempotentException;
import com.bf.electroplating.login.UserContext;
import com.bf.electroplating.login.UserDetail;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class IdempotentAspect {

    @Value("${idempotent.timeout:5}")
    private long defaultTimeout;

    @Autowired
    private RedisTemplate redisTemplate;

    @Around("@annotation(com.bf.electroplating.util.idempotent.Idempotent)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Idempotent idempotent = method.getAnnotation(Idempotent.class);

        // 从上下文中获取当前用户
        UserDetail user = UserContext.getUser();
        if (user == null) {
            throw new RuntimeException("用户未登录");
        }

        // 生成幂等键: user:{userId}:{className}:{methodName}:{bizKey}
        String key = String.format("user:%s:%s.%s:%s",
                user.getId(),
                method.getDeclaringClass().getSimpleName(),
                method.getName(),
                idempotent.bizKey()
        );

        // 检查是否已处理过
        Boolean isNew = redisTemplate.opsForValue().setIfAbsent(
                key,
                System.currentTimeMillis(),
                defaultTimeout,
                TimeUnit.SECONDS
        );

        if (Boolean.FALSE.equals(isNew)) {
            throw new IdempotentException(idempotent.message());
        }

        try {
            return joinPoint.proceed();
        } finally {
            // 可选：方法执行后删除锁（适用于需要长时间处理的情况）
            // redisTemplate.delete(key);
        }
    }
}
